﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.IO;
using FileDownloaderApp;
using System.IO.Compression;
using System.Diagnostics;
using System.Threading.Tasks;
using System.ComponentModel;
using Ionic.Zip;
using System.Threading;
using System.Security.Cryptography;

namespace BoonCraft1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        string path = null;
        double version = 0;
        FileDownloader fd = null;
        List<FileDownloader.FileInfo> filelist = new List<FileDownloader.FileInfo>();
        int completeCount = 0;
        int totalFiles = 0;
        bool zipping = false;
        string username = null;
        const string quote = "\"";

        public MainWindow()
        {
            InitializeComponent();
            path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).ToString()) + "\\.booncraft\\";
            createDirs();
            loadSettings();
        }

        private void createDirs()
        {
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            if (!Directory.Exists(path + "downloads\\"))
            {
                Directory.CreateDirectory(path + "downloads\\");
            }
            if (!Directory.Exists(path + "bin\\"))
            {
                Directory.CreateDirectory(path + "bin\\");
            }
            if (!Directory.Exists(path + ".minecraft\\"))
            {
                Directory.CreateDirectory(path + ".minecraft\\");
            }
            if (!Directory.Exists(path + ".minecraft\\resources"))
            {
                Directory.CreateDirectory(path + ".minecraft\\resources");
            }
        }

        private void loadSettings()
        {
            try
            {
                string[] lines = File.ReadAllLines(path + "lastlogin");
                txtUsername.Text = lines[0];
                Password.Password = encryption.DecryptString(lines[1], "BoonCraft");
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
            try
            {
                string[] lines = File.ReadAllLines(path + "options.cfg");
                foreach (string x in lines)
                {
                    switch (x.Split(':')[0])
                    {
                        case "saveLogin":
                            if (x.Split(':').Length == 2)
                            {
                                SaveLoginCHK.IsChecked = Convert.ToBoolean(x.Split(':')[1]);
                            }
                            break;
                        case "offlineMode":
                            if (x.Split(':').Length == 2)
                            {
                                OfflineModeCHK.IsChecked = Convert.ToBoolean(x.Split(':')[1]);
                            }
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
                SaveOptions_Click(null, null);
            }
        }

        private void SaveOptions_Click(object sender, RoutedEventArgs e)
        {
            string[] lines = new string[2] { "saveLogin:" + SaveLoginCHK.IsChecked, "offlineMode:" + OfflineModeCHK.IsChecked };
            File.WriteAllLines(path + "options.cfg", lines);
        }

        private void btnLogin_Click(object sender, RoutedEventArgs e)
        {
            double curVersion = 0.0;
            if (File.Exists(path + ".minecraft/version"))
                curVersion = Convert.ToDouble(File.ReadAllText(path + ".minecraft/version"));
            if ((string)btnLogin.Content == "Login" && version > curVersion)
            {
                btnLogin.IsEnabled = false;
                fd = new FileDownloader(true);
                fd.ProgressChanged += new EventHandler(downloader_ProgressChanged);
                fd.StopWatchCyclesAmount = 50;
                fd.FileDownloadSucceeded += new EventHandler(downloader_FileComplete);
                fd.Completed += new EventHandler(downloader_Complete);
                fd.LocalDirectory = path + "downloads\\";
                fd.Files.Clear();
                fd.Files.AddRange(filelist);
                fd.Start();
            }
            else
            {
                startMC();
            }
        }

        private void startMC()
        {
            if (OfflineModeCHK.IsChecked == true)
            {
                startOffline();
            }
            else
            {
                startOnline();
            }
        }

        private string getSessionID()
        {
            WebClient client = new WebClient();
            string retrieved = client.DownloadString("https://login.minecraft.net/?user=" + txtUsername.Text + "&password=" + Password.Password + "&version=12");
            string[] data = retrieved.Split(':');
            Console.WriteLine(retrieved);
            if (data.Length == 4)
            {
                username = data[2];
                return data[3];
            }
            else
                return null;
        }

        private void startOnline()
        {
            string appdatapath = @"" + path + @"";
            string sessionID = getSessionID();
            if (sessionID != null)
            {
                if (SaveLoginCHK.IsChecked == true)
                {
                    File.WriteAllLines(path + "lastlogin", new string[] { username, encryption.EncryptString(Password.Password, "BoonCraft") });
                }
                string command = "java -jar " + quote + path + "Launcherv1.jar" + quote + " " + username + " " + sessionID + " 1";
                ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
                procStartInfo.UseShellExecute = false;
                procStartInfo.CreateNoWindow = false;
                procStartInfo.EnvironmentVariables.Remove("APPDATA");
                procStartInfo.EnvironmentVariables.Add("APPDATA", appdatapath);
                Process p = new Process();
                p.StartInfo = procStartInfo;
                p.Start();
                this.Close();
            }
            else
            {
                MessageBoxResult res = MessageBox.Show("        Invalid Login Details entered!\n Do you want to playing offline mode?", "Invalid Login", MessageBoxButton.YesNo);
                if (res == MessageBoxResult.Yes)
                {
                    startOffline();
                }
                else
                {
                    btnLogin.Content = "Starting...";
                    btnLogin.IsEnabled = true;
                }
            }
        }

        private void startOffline()
        {
            string appdatapath = @"" + path + @"";
            if (txtUsername.Text.Trim() != "")
            {
                string command = "java -jar " + quote + path + "Launcherv1.jar" + quote + " " + txtUsername.Text + " 1" + " 1";
                ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
                procStartInfo.UseShellExecute = false;
                procStartInfo.CreateNoWindow = false;
                procStartInfo.EnvironmentVariables.Remove("APPDATA");
                procStartInfo.EnvironmentVariables.Add("APPDATA", appdatapath);
                Process p = new Process();
                p.StartInfo = procStartInfo;
                p.Start();
                this.Close();
            }
            else
            {
                string command = "java -jar " + quote + path + "Launcherv1.jar" + quote + " Player" + " 1" + " 1";
                ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
                procStartInfo.UseShellExecute = false;
                procStartInfo.CreateNoWindow = false;
                procStartInfo.EnvironmentVariables.Remove("APPDATA");
                procStartInfo.EnvironmentVariables.Add("APPDATA", appdatapath);
                Process p = new Process();
                p.StartInfo = procStartInfo;
                p.Start();
                this.Close();
            }
        }

        private void getVersionandFiles()
        {
            try
            {
                WebClient client = new WebClient();
                string data = client.DownloadString("http://352n.dyndns-server.com/ClientLauncherDownloads/version.txt");
                if (data != null)
                {
                    string[] files = data.Split('\n');
                    version = Convert.ToDouble(files[0]);
                    for (int x = 1; x < files.Length; x++)
                    {
                        filelist.Add(new FileDownloader.FileInfo(files[x]));
                    }
                    Console.WriteLine("Version: " + version);
                    Console.WriteLine("Files: " + (files.Length - 1));
                    totalFiles = files.Length - 1;
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

        }

        private void Window_Loaded_2(object sender, RoutedEventArgs e)
        {
            getVersionandFiles();
        }

        private void downloader_ProgressChanged(object sender, EventArgs e)
        {
            if (fd.CurrentFilePercentage() <= 100)
                pBarFileProgress.Value = fd.CurrentFilePercentage();
            lblFileProgress.Content = String.Format("Downloaded {0} of {1} ({2}%)",
            FileDownloader.FormatSizeBinary(fd.CurrentFileProgress),
            FileDownloader.FormatSizeBinary(fd.CurrentFileSize),
            fd.CurrentFilePercentage()) + String.Format(" - {0}/s",
            FileDownloader.FormatSizeBinary(fd.DownloadSpeed));

            if (fd.SupportsProgress)
            {
                pBarTotalProgress.Value = fd.TotalPercentage();
                lblTotalProgress.Content = String.Format("Downloaded {0} of {1} ({2}%)",
                FileDownloader.FormatSizeBinary(fd.TotalProgress),
                FileDownloader.FormatSizeBinary(fd.TotalSize),
                fd.TotalPercentage());
            }
        }

        private void downloader_FileComplete(object _sender, EventArgs e)
        {
            completeCount += 1;
            FileDownloader sender = (FileDownloader)_sender;
            FileDownloader.FileInfo file = sender.Files[completeCount - 1];
            if (file.Name == "minecraft.jar")
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += new DoWorkEventHandler(minecraftJar);
                bw.RunWorkerAsync();
            }
            else if (file.Name == "resources.zip")
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += new DoWorkEventHandler(resourcesZip);
                bw.RunWorkerAsync();
            }
            else if (file.Name == "windows_natives.jar")
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += new DoWorkEventHandler(nativesZip);
                bw.RunWorkerAsync();
            }
            else if (file.Name == "ClassFiles.zip")
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += new DoWorkEventHandler(classFilesZip);
                bw.RunWorkerAsync();
            }
            else if (file.Path.StartsWith("https://s3.amazonaws.com/MinecraftDownload/"))
            {
                if (File.Exists(path + "/bin/" + file.Name))
                {
                    File.Delete(path + "/bin/" + file.Name);
                }
                File.Move(sender.LocalDirectory + file.Name, path + "/bin/" + file.Name);
            }
            else if (file.Path.StartsWith("http://352n.dyndns-server.com/ClientLauncherDownloads/booncraft"))
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += new DoWorkEventHandler(mainZip);
                bw.RunWorkerAsync(file.Name);
            }
            else if (file.Path.StartsWith("http://352n.dyndns-server.com/ClientLauncherDownloads/"))
            {
                if (File.Exists(path + file.Name))
                {
                    File.Delete(path + file.Name);
                }
                File.Move(sender.LocalDirectory + file.Name, path + file.Name);
            }
        }

        private void nativesZip(object sender, DoWorkEventArgs e)
        {
            zipping = true;
            if (!Directory.Exists(path + @"/bin/natives/"))
            {
                Directory.CreateDirectory(path + @"/bin/natives/");
            }
            unZip(fd.LocalDirectory + "windows_natives.jar", path + @"/bin/natives/");
            File.Delete(fd.LocalDirectory + "windows_natives.jar");
            zipping = false;
        }

        private void downloader_Complete(object _sender, EventArgs e)
        {
            while (zipping)
            {
                System.Threading.Thread.Sleep(200);
            }
            btnLogin.Content = "Start BoonCraft";
            btnLogin.IsEnabled = true;
        }

        private void resourcesZip(object sender, DoWorkEventArgs e)
        {
            zipping = true;
            if (!Directory.Exists(path + @"/.minecraft"))
            {
                Directory.CreateDirectory(path + @"/.minecraft");
            }
            unZip(fd.LocalDirectory + "resources.zip", path + @"/.minecraft");
            File.Delete(fd.LocalDirectory + "resources.zip");
            zipping = false;
        }

        private void mainZip(object sender, DoWorkEventArgs e)
        {
            zipping = true;
            string filename = (string)e.Argument;
            if (!Directory.Exists(path + @"/.minecraft"))
            {
                Directory.CreateDirectory(path + @"/.minecraft");
            }
            unZip(fd.LocalDirectory + filename, path + @"/.minecraft");
            File.Delete(fd.LocalDirectory + filename);
            zipping = false;
        }

        public void classFilesZip(object sender, DoWorkEventArgs e)
        {
            zipping = true;
            if (!Directory.Exists(path + @"/bin/temp"))
            {
                Directory.CreateDirectory(path + @"/bin/temp");
            }
            unZip(fd.LocalDirectory + "ClassFiles.zip", path + @"/bin/temp");
            File.Delete(fd.LocalDirectory + "ClassFiles.zip");
            for (int x = 0; x < fd.Files.Count; x++)
            {
                if (fd.Files[x].Name == "ClassFiles.zip")
                {
                    Directory.Delete(path + @"/bin/temp/META-INF", true);
                    break;
                }
                else if (fd.Files[x].Name == "minecraft.jar")
                {
                    zipFolder(path + @"/bin/temp", path + @"/bin/minecraft.jar");
                    Directory.Delete(path + @"/bin/temp", true);
                    break;
                }
            }
            zipping = false;
        }

        public void minecraftJar(object sender, DoWorkEventArgs e)
        {
            zipping = true;
            if (!Directory.Exists(path + @"/bin/temp"))
            {
                Directory.CreateDirectory(path + @"/bin/temp");
            }
            unZip(fd.LocalDirectory + "minecraft.jar", path + @"/bin/temp");
            File.Delete(fd.LocalDirectory + "minecraft.jar");
            for (int x = 0; x < fd.Files.Count; x++)
            {
                if (fd.Files[x].Name == "minecraft.jar")
                {
                    Directory.Delete(path + @"/bin/temp/META-INF", true);
                    break;
                }
                else if (fd.Files[x].Name == "ClassFiles.zip")
                {
                    zipFolder(path + @"/bin/temp", path + @"/bin/minecraft.jar");
                    Directory.Delete(path + @"/bin/temp", true);
                    break;
                }
            }
            zipping = false;
        }

        #region "Compression"
        void zipFolder(string folder, string location)
        {
            using (ZipFile zip = new ZipFile())
            {
                // add all those files to the ProjectX folder in the zip file
                zip.AddDirectory(folder);
                zip.Comment = "This zip was created at " + System.DateTime.Now.ToString("G");
                zip.Save(location);
            }
        }

        void unZip(string file, string location)
        {
            using (ZipFile zip = ZipFile.Read(file))
            {
                foreach (ZipEntry files in zip)
                {
                    files.Extract(location, ExtractExistingFileAction.OverwriteSilently);
                }
            }
        }

        #endregion




    }

    class encryption
    {
        public static string EncryptString(string Message, string Passphrase)
        {
            byte[] Results;
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            // Step 1. We hash the passphrase using MD5
            // We use the MD5 hash generator as the result is a 128 bit byte array
            // which is a valid length for the TripleDES encoder we use below

            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));

            // Step 2. Create a new TripleDESCryptoServiceProvider object
            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Step 3. Setup the encoder
            TDESAlgorithm.Key = TDESKey;
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Step 4. Convert the input string to a byte[]
            byte[] DataToEncrypt = UTF8.GetBytes(Message);

            // Step 5. Attempt to encrypt the string
            try
            {
                ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
                Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
            }
            finally
            {
                // Clear the TripleDes and Hashprovider services of any sensitive information
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            // Step 6. Return the encrypted string as a base64 encoded string
            return Convert.ToBase64String(Results);
        }

        public static string DecryptString(string Message, string Passphrase)
        {
            byte[] Results;
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            // Step 1. We hash the passphrase using MD5
            // We use the MD5 hash generator as the result is a 128 bit byte array
            // which is a valid length for the TripleDES encoder we use below

            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));

            // Step 2. Create a new TripleDESCryptoServiceProvider object
            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Step 3. Setup the decoder
            TDESAlgorithm.Key = TDESKey;
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Step 4. Convert the input string to a byte[]
            byte[] DataToDecrypt = Convert.FromBase64String(Message);

            // Step 5. Attempt to decrypt the string
            try
            {
                ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();
                Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
            }
            finally
            {
                // Clear the TripleDes and Hashprovider services of any sensitive information
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            // Step 6. Return the decrypted string in UTF8 format
            return UTF8.GetString(Results);
        }
    }
}
